<<<<<<< HEAD
"""
import sys

sys.path.append("YourAddress")
"""
import ctypes
import inspect
import pygame
import time
import threading
import pdb
from Model.Interface.Button import Button
from Model.Interface.Image import Image
from Model.Interface.Info import Info
from Model.Logic.Battle_state import Battle_state, battle_state_detail
from Model.Logic.Role import Monster, Player
from Model.Logic.Round import Round
from Model.Logic.Skill import Skill

state = 1

def _async_raise(tid, exec_type):
    """
    杀死线程
    raises the exception, performs cleanup if needed
    """
    tid = ctypes.c_long(tid)
    if not inspect.isclass(exec_type):
        exec_type = type(exec_type)
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exec_type))
    if res == 0:
        raise ValueError("invalid thread id")
    elif res != 1:
        # """if it returns a number greater than one, you're in trouble,
        # and you should call it again with exc=NULL to revert the effect"""
        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
        raise SystemError("PyThreadState_SetAsyncExc failed")


def stop_thread(thread):
    _async_raise(thread.ident, SystemExit)


class Battle:
    class Battle_interface:
        def __init__(self, player, monster, battle):
            """
            战斗逻辑层初始化
            :param player: 玩家
            :param monster: 怪物
            :param battle: 战斗类，方便拿外部类的公有属性
            """
            self.player = player
            self.monster = monster
            self.battle = battle

        def start(self):
            """
            逻辑启动
            :return: 无
            """
            # 初始化pygame，我塞__init__里会爆bug，拿不到处理过的pygame, 不晓得为什么
            global state
            run = True
            pygame.init()

            # 初始化屏幕
            screen = pygame.display.set_mode([800, 600])
            pygame.display.set_caption("史莱姆大战勇士")

            # 初始化按钮类、图片类和信息类
            button = Button(pygame, screen, self.player)
            image = Image(pygame, screen, self.monster.image, self.player.image)
            info = Info(pygame, screen, self.monster.basic_info(), self.player.basic_info())
            while(run):
                if (state == 1):
                        print(state)
                        # 提取键盘操作一些相关初始化
                        init(screen)
                        # 人物移动
                        playerMove()
                        # 根据一些已知条件进行场景渲染
                        checkRander(screen)
                        pygame.display.update()
                # pygame事件循环
                if (state == 2):

                    for event in pygame.event.get():
                        # 如果点右上角，设定循环条件为否
                        if event.type == pygame.QUIT:
                            run = False
                        # 如果有点击事件
                        if event.type == pygame.MOUSEBUTTONDOWN:
                             # 调用按钮类的检查函数，会去判断点击的坐标是不是在按钮上，并判断点的是哪个技能按钮
                            tmp_skill_id = button.check_button_coordinate(event)
                            # 如果点的是按钮
                            if tmp_skill_id is not None:
                                self.battle.skill_id = tmp_skill_id
                                # 释放逻辑层的技能等待锁
                                self.battle.skill_choose_event.set()

                                # 重置本轮信息锁为锁定，并等待逻辑层响应
                                self.battle.round_info_event.clear()
                                self.battle.round_info_event.wait()

                                # 拿到逻辑层信息后，更新血条蓝条
                                info.update_info(
                                    self.battle.round_info["monster_info"],
                                    self.battle.round_info["player_info"]
                                )
                                # 更新技能状况，蓝不够的技能会变灰
                                button.update_button_list(self.player)

                    image.load_image()
                    info.load_text()
                    button.load_button()
                    pygame.display.update()
            if(state == 2):
                pygame.quit()
                # 用户主动关闭窗口，先释放逻辑层的锁，再杀死逻辑线程
                self.battle.skill_choose_event.set()
                stop_thread(self.battle.logic)

    class Battle_logic:
        def __init__(self, player, monster, battle):
            """
            逻辑层初始化
            :param player: 玩家对象
            :param monster: 怪物对象
            :param battle: 战斗类，拿公有属性和方法
            """
            self.player = player
            self.monster = monster
            self.battle = battle

            # 初始化round类，并设定战斗结果为-2，意味着异常退出
            self.game_round = Round(player, monster)
            self._result = -2

        def round_status_print(self, round_result):
            """
            本轮信息log打印函数
            :param round_result:
            :return:
            """
            game_round = self.game_round
            print(f"""
            {game_round},
            {battle_state_detail(round_result["battle_state"])}

            当前{self.player}
            血量为{round_result["round_info"]["player_info"]["hp_current"]},
            魔法量为{round_result["round_info"]["player_info"]["mp_current"]}

            {self.monster}
            血量为{round_result["round_info"]["monster_info"]["hp_current"]},
            魔法量为{round_result["round_info"]["monster_info"]["mp_current"]}
            """)

        def round_damage_print(self, round_result):
            """
            伤害打印函数
            :param round_result:
            :return:
            """
            print(f"""
            {self.player}对{self.monster}造成了{round_result["damage"]["by_player"]}伤害
            {self.monster}对{self.player}造成了{round_result["damage"]["by_monster"]}伤害
            """)

        def start(self):
            """
            逻辑层启动
            :return:
            """
            global state
            game_round = self.game_round
            round_result = dict()
            round_result["battle_state"] = Battle_state.be_in_progress

            # 如果游戏未结束，则继续循环
            while round_result["battle_state"] == Battle_state.be_in_progress:
                # 第一轮不打印信息
                if game_round.count:
                    self.round_status_print(round_result)
                    self.round_damage_print(round_result)
                game_round.count += 1

                # 重置技能选择锁，等待用户在界面上的操作
                self.battle.skill_choose_event.clear()
                self.battle.skill_choose_event.wait()

                # 技能选择锁释放后，计算这轮的伤害和角色当前信息，信息是储存在外部公有属性里的
                round_result = game_round.exec(self.battle.skill_id)
                self.battle.round_info = round_result["round_info"]
                # 释放本轮信息锁
                self.battle.round_info_event.set()

            # 战斗结束，打印最终结果，并休眠两秒，以免退出太快看不清
            self.round_status_print(round_result)
            time.sleep(2)
            # 更新battle_state信息
            self._result = round_result["battle_state"]
            state = 1
            stop_thread(self.battle.interface)

        def get_result(self):
            """
            获取战斗结果，以调用exp函数
            :return:
            """
            return battle_state_detail(self._result)

    def __init__(self, player, monster):
        """
        战斗类初始化，负责储藏公有属性，和初始化逻辑层和界面层线程
        :param player: 玩家对象
        :param monster: 怪物对象
        """
        self.player = player
        self.monster = monster

        # 初始化两把进程锁
        self.skill_choose_event = threading.Event()
        self.round_info_event = threading.Event()
        # 技能id和战斗信息，作为公有信息，因为两个线程都需要使用
        self.skill_id = 0
        self.round_info = {}

        # 初始化两个类
        self.battle_logic = self.Battle_logic(self.player, self.monster, self)
        self.battle_interface = self.Battle_interface(self.player, self.monster, self)
        # 初始化它们的线程
        self.logic = threading.Thread(target=self.battle_logic.start)
        self.interface = threading.Thread(target=self.battle_interface.start)


    def run(self):
        global state
        # 线程启动
        self.logic.start()
        self.interface.start()
        # 阻塞主线程
        self.logic.join()
        self.interface.join()
        # 返回战斗结果状态码
        if(self.battle_logic.get_result() == 1):
            state = 1
        return self.battle_logic.get_result()


#pygame.display.set_caption('background')

player_l = pygame.image.load("link.png")#玩家
player_r = pygame.image.load("link_r.png")#玩家
bgImg1 = pygame.image.load("village.png")#场景一
bgImg2 = pygame.image.load("battle.png")#场景二
playerX = 150
playerY = 500
playerStep1 = 0
playerStep2 = 0
Running = True
scene1 = True
scene2 = False
left = False
right = False

# 场景渲染和人物渲染，第一个参数表示场景编号，第二个参数表示人物面朝方向

def sceneRender(mapID, action,screen):

    screen.blit(mapID, (0, 0))
    screen.blit(action, (playerX, playerY))
# 人物移动，以及判断出界情况
def playerMove():
    global playerX, playerY, scene1, scene2, playerStep1, playerStep2
    playerX += playerStep1
    playerY += playerStep2
    if playerX > 800:                  #人物移动范围
      playerX = 50
      scene2 = True
      scene1 = False
    if playerX < 0:
      playerX = 600
      scene1 = True
      scene2 = False
    #if playerY > 600:
    #  playerY = 600
    #if playerY < 400:
    #  playerY = 400
# 初始化，响应相关键盘操作比如控制移动
def init(screen):
    global playerX, playerY, scene1, scene2, playerStep1, playerStep2, left, right
    sceneRender(bgImg1,player_r,screen)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            Running = False
            pygame.quit()
            pdb.set_trace()
        if event.type == pygame.KEYDOWN:#键盘操作位置
          if event.key == pygame.K_RIGHT:
               playerStep1 = 5
               left = False
               right = True
          elif event.key == pygame.K_LEFT:
               playerStep1 = -5
               left = True
               right = False
          if event.key == pygame.K_UP:
               playerStep2 = -2
          elif event.key == pygame.K_DOWN:
               playerStep2 = 2
        if event.type == pygame.KEYUP:
               playerStep1 = 0
               playerStep2 = 0
# 场景切换
def checkRander(screen):
    global scene1, scene2, left, right,state
    # 第1场——村庄
    if scene1 and left:
      sceneRender(bgImg1, player_l,screen)
    if scene1 and right:
      sceneRender(bgImg1, player_r,screen)
    # 第2场景 打怪
    if scene2 and left:
      state = 2                         #场景切换
      #sceneRender(bgImg2, player_l,screen)
    if scene2 and right:
      state = 2
      #sceneRender(bgImg2, player_r,screen)

def test():
    """
    测试方法
    :return:
    """
    monster_test = Monster(
        name="骑士",
        level=1,
        hp=100,
        mp=25,
        attack=25,
        defence=15,
        speed=1,
        skill_list=[
            Skill("盾击", 20, 12),
            Skill("挥砍", 30, 15)
        ],
        image="/Image/Role/knight.png"
    )
    player_test = Player(
        name="史莱姆",
        level=1,
        exp=0,
        hp=100,
        mp=100,
        attack=30,
        defence=10,
        speed=3,
        skill_list=[
            Skill("粘液喷吐", 10, 30),
            Skill("肉弹冲击", 25, 50),
            Skill("猛击", 35, 80)
        ],
        image="/Image/Role/slime.png"
    )
    battle_test = Battle(player_test, monster_test)
    print(battle_test.run())


if __name__ == '__main__':
    test()
=======
"""
import sys

sys.path.append("YourAddress")
"""
import ctypes
import inspect
import pygame
import time
import threading
import pdb
from Model.Interface.Button import Button
from Model.Interface.Image import Image
from Model.Interface.Info import Info
from Model.Logic.Battle_state import Battle_state, battle_state_detail
from Model.Logic.Role import Monster, Player
from Model.Logic.Round import Round
from Model.Logic.Skill import Skill

state = 1

def _async_raise(tid, exec_type):
    """
    杀死线程
    raises the exception, performs cleanup if needed
    """
    tid = ctypes.c_long(tid)
    if not inspect.isclass(exec_type):
        exec_type = type(exec_type)
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exec_type))
    if res == 0:
        raise ValueError("invalid thread id")
    elif res != 1:
        # """if it returns a number greater than one, you're in trouble,
        # and you should call it again with exc=NULL to revert the effect"""
        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
        raise SystemError("PyThreadState_SetAsyncExc failed")


def stop_thread(thread):
    _async_raise(thread.ident, SystemExit)


class Battle:
    class Battle_interface:
        def __init__(self, player, monster, battle):
            """
            战斗逻辑层初始化
            :param player: 玩家
            :param monster: 怪物
            :param battle: 战斗类，方便拿外部类的公有属性
            """
            self.player = player
            self.monster = monster
            self.battle = battle

        def start(self):
            """
            逻辑启动
            :return: 无
            """
            # 初始化pygame，我塞__init__里会爆bug，拿不到处理过的pygame, 不晓得为什么
            global state
            run = True
            pygame.init()

            # 初始化屏幕
            screen = pygame.display.set_mode([800, 600])
            pygame.display.set_caption("史莱姆大战勇士")

            # 初始化按钮类、图片类和信息类
            button = Button(pygame, screen, self.player)
            image = Image(pygame, screen, self.monster.image, self.player.image)
            info = Info(pygame, screen, self.monster.basic_info(), self.player.basic_info())
            while(run):
                if (state == 1):
                        print(state)
                        # 提取键盘操作一些相关初始化
                        init(screen)
                        # 人物移动
                        playerMove()
                        # 根据一些已知条件进行场景渲染
                        checkRander(screen)
                        pygame.display.update()
                # pygame事件循环
                if (state == 2):

                    for event in pygame.event.get():
                        # 如果点右上角，设定循环条件为否
                        if event.type == pygame.QUIT:
                            run = False
                        # 如果有点击事件
                        if event.type == pygame.MOUSEBUTTONDOWN:
                             # 调用按钮类的检查函数，会去判断点击的坐标是不是在按钮上，并判断点的是哪个技能按钮
                            tmp_skill_id = button.check_button_coordinate(event)
                            # 如果点的是按钮
                            if tmp_skill_id is not None:
                                self.battle.skill_id = tmp_skill_id
                                # 释放逻辑层的技能等待锁
                                self.battle.skill_choose_event.set()

                                # 重置本轮信息锁为锁定，并等待逻辑层响应
                                self.battle.round_info_event.clear()
                                self.battle.round_info_event.wait()

                                # 拿到逻辑层信息后，更新血条蓝条
                                info.update_info(
                                    self.battle.round_info["monster_info"],
                                    self.battle.round_info["player_info"]
                                )
                                # 更新技能状况，蓝不够的技能会变灰
                                button.update_button_list(self.player)

                    image.load_image()
                    info.load_text()
                    button.load_button()
                    pygame.display.update()
            if(state == 2):
                pygame.quit()
                # 用户主动关闭窗口，先释放逻辑层的锁，再杀死逻辑线程
                self.battle.skill_choose_event.set()
                stop_thread(self.battle.logic)

    class Battle_logic:
        def __init__(self, player, monster, battle):
            """
            逻辑层初始化
            :param player: 玩家对象
            :param monster: 怪物对象
            :param battle: 战斗类，拿公有属性和方法
            """
            self.player = player
            self.monster = monster
            self.battle = battle

            # 初始化round类，并设定战斗结果为-2，意味着异常退出
            self.game_round = Round(player, monster)
            self._result = -2

        def round_status_print(self, round_result):
            """
            本轮信息log打印函数
            :param round_result:
            :return:
            """
            game_round = self.game_round
            print(f"""
            {game_round},
            {battle_state_detail(round_result["battle_state"])}

            当前{self.player}
            血量为{round_result["round_info"]["player_info"]["hp_current"]},
            魔法量为{round_result["round_info"]["player_info"]["mp_current"]}

            {self.monster}
            血量为{round_result["round_info"]["monster_info"]["hp_current"]},
            魔法量为{round_result["round_info"]["monster_info"]["mp_current"]}
            """)

        def round_damage_print(self, round_result):
            """
            伤害打印函数
            :param round_result:
            :return:
            """
            print(f"""
            {self.player}对{self.monster}造成了{round_result["damage"]["by_player"]}伤害
            {self.monster}对{self.player}造成了{round_result["damage"]["by_monster"]}伤害
            """)

        def start(self):
            """
            逻辑层启动
            :return:
            """
            global state
            game_round = self.game_round
            round_result = dict()
            round_result["battle_state"] = Battle_state.be_in_progress

            # 如果游戏未结束，则继续循环
            while round_result["battle_state"] == Battle_state.be_in_progress:
                # 第一轮不打印信息
                if game_round.count:
                    self.round_status_print(round_result)
                    self.round_damage_print(round_result)
                game_round.count += 1

                # 重置技能选择锁，等待用户在界面上的操作
                self.battle.skill_choose_event.clear()
                self.battle.skill_choose_event.wait()

                # 技能选择锁释放后，计算这轮的伤害和角色当前信息，信息是储存在外部公有属性里的
                round_result = game_round.exec(self.battle.skill_id)
                self.battle.round_info = round_result["round_info"]
                # 释放本轮信息锁
                self.battle.round_info_event.set()

            # 战斗结束，打印最终结果，并休眠两秒，以免退出太快看不清
            self.round_status_print(round_result)
            time.sleep(2)
            # 更新battle_state信息
            self._result = round_result["battle_state"]
            state = 1
            stop_thread(self.battle.interface)

        def get_result(self):
            """
            获取战斗结果，以调用exp函数
            :return:
            """
            return battle_state_detail(self._result)

    def __init__(self, player, monster):
        """
        战斗类初始化，负责储藏公有属性，和初始化逻辑层和界面层线程
        :param player: 玩家对象
        :param monster: 怪物对象
        """
        self.player = player
        self.monster = monster

        # 初始化两把进程锁
        self.skill_choose_event = threading.Event()
        self.round_info_event = threading.Event()
        # 技能id和战斗信息，作为公有信息，因为两个线程都需要使用
        self.skill_id = 0
        self.round_info = {}

        # 初始化两个类
        self.battle_logic = self.Battle_logic(self.player, self.monster, self)
        self.battle_interface = self.Battle_interface(self.player, self.monster, self)
        # 初始化它们的线程
        self.logic = threading.Thread(target=self.battle_logic.start)
        self.interface = threading.Thread(target=self.battle_interface.start)


    def run(self):
        global state
        # 线程启动
        self.logic.start()
        self.interface.start()
        # 阻塞主线程
        self.logic.join()
        self.interface.join()
        # 返回战斗结果状态码
        if(self.battle_logic.get_result() == 1):
            state = 1
        return self.battle_logic.get_result()


#pygame.display.set_caption('background')

player_l = pygame.image.load("link.png")#玩家
player_r = pygame.image.load("link_r.png")#玩家
bgImg1 = pygame.image.load("village.png")#场景一
bgImg2 = pygame.image.load("battle.png")#场景二
playerX = 150
playerY = 500
playerStep1 = 0
playerStep2 = 0
Running = True
scene1 = True
scene2 = False
left = False
right = False

# 场景渲染和人物渲染，第一个参数表示场景编号，第二个参数表示人物面朝方向

def sceneRender(mapID, action,screen):

    screen.blit(mapID, (0, 0))
    screen.blit(action, (playerX, playerY))
# 人物移动，以及判断出界情况
def playerMove():
    global playerX, playerY, scene1, scene2, playerStep1, playerStep2
    playerX += playerStep1
    playerY += playerStep2
    if playerX > 800:                  #人物移动范围
      playerX = 50
      scene2 = True
      scene1 = False
    if playerX < 0:
      playerX = 600
      scene1 = True
      scene2 = False
    #if playerY > 600:
    #  playerY = 600
    #if playerY < 400:
    #  playerY = 400
# 初始化，响应相关键盘操作比如控制移动
def init(screen):
    global playerX, playerY, scene1, scene2, playerStep1, playerStep2, left, right
    sceneRender(bgImg1,player_r,screen)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            Running = False
            pygame.quit()
            pdb.set_trace()
        if event.type == pygame.KEYDOWN:#键盘操作位置
          if event.key == pygame.K_RIGHT:
               playerStep1 = 5
               left = False
               right = True
          elif event.key == pygame.K_LEFT:
               playerStep1 = -5
               left = True
               right = False
          if event.key == pygame.K_UP:
               playerStep2 = -2
          elif event.key == pygame.K_DOWN:
               playerStep2 = 2
        if event.type == pygame.KEYUP:
               playerStep1 = 0
               playerStep2 = 0
# 场景切换
def checkRander(screen):
    global scene1, scene2, left, right,state
    # 第1场——村庄
    if scene1 and left:
      sceneRender(bgImg1, player_l,screen)
    if scene1 and right:
      sceneRender(bgImg1, player_r,screen)
    # 第2场景 打怪
    if scene2 and left:
      state = 2                         #场景切换
      #sceneRender(bgImg2, player_l,screen)
    if scene2 and right:
      state = 2
      #sceneRender(bgImg2, player_r,screen)

def test():
    """
    测试方法
    :return:
    """
    monster_test = Monster(
        name="骑士",
        level=1,
        hp=100,
        mp=25,
        attack=25,
        defence=15,
        speed=1,
        skill_list=[
            Skill("盾击", 20, 12),
            Skill("挥砍", 30, 15)
        ],
        image="/Image/Role/knight.png"
    )
    player_test = Player(
        name="史莱姆",
        level=1,
        exp=0,
        hp=100,
        mp=100,
        attack=30,
        defence=10,
        speed=3,
        skill_list=[
            Skill("粘液喷吐", 10, 30),
            Skill("肉弹冲击", 25, 50),
            Skill("猛击", 35, 80)
        ],
        image="/Image/Role/slime.png"
    )
    battle_test = Battle(player_test, monster_test)
    print(battle_test.run())


if __name__ == '__main__':
    test()
>>>>>>> 94cb98322753a8bfa7c40436c4d875db975d48f7
